//
//  MoveConsAndAssign2.hpp
//  learnC++
//
//  Created by liuzhibing on 2018/6/28.
//  Copyright © 2018年 yunfan.com. All rights reserved.
//

#ifndef MoveConsAndAssign2_hpp
#define MoveConsAndAssign2_hpp

#include <stdio.h>
#include <iostream>

//Auto_ptr4是（最后）一个很好的智能指针类。 实际上，标准库包含一个非常类似于此类的类（您应该使用它），名为std :: unique_ptr。 本章稍后会详细讨论std :: unique_ptr。
//unique(只存在唯一的一个内容刚好和移动语义一个意思)
template <class T>
class AutoPtr4 {
    T *m_ptr;
    
public:
    
    AutoPtr4(T *ptr=nullptr):m_ptr(ptr){
        
    }
    
    ~AutoPtr4(){
        
        delete m_ptr;
    }
    
    //禁用复制构造函数和赋值函数
//    如果您尝试通过值将Auto_ptr4 l值传递给函数，编译器会抱怨复制构造函数参数初始化所需的复制构造函数已被删除。 这很好，因为我们可能应该通过const l-value引用传递Auto_ptr4！
    AutoPtr4(const AutoPtr4 &p) = delete;
//    AutoPtr4(const AutoPtr4 &p){
//        m_ptr = new T;
//        *m_ptr = *p.m_ptr;
//    }
    
    AutoPtr4 &operator=(const AutoPtr4 &p) = delete;
//    AutoPtr4 &operator=(const AutoPtr4 &p){
//        if (&p == this) {
//            return *this;
//        }
//
//        delete m_ptr;
//
//        m_ptr = new T;
//        *m_ptr = *p.m_ptr;
//        return *this;
//    }
    
//    如果我们构造一个对象或者在参数是一个l值的情况下做一个赋值，我们可以合理做的唯一的事情就是复制l值。我们不能认为改变l值是安全的，因为它可能会在程序中稍后再次使用。如果我们有一个表达式“a = b”，我们不会合理地期望b以任何方式被改变。
//    然而，如果我们构造一个对象或者在参数是一个r值的情况下进行赋值，那么我们知道r值只是某种临时对象。我们可以简单地将其资源（这很便宜）转移到我们正在构建或分配的对象上，而不是复制它（可能很昂贵）。这样做是安全的，因为无论如何临时表达式都会被销毁，所以我们知道它永远不会再被使用！
//    通过r值引用，C ++ 11使我们能够在参数是r值和l值时提供不同的行为，从而使我们能够做出更明智，更有效的关于对象如何表现的决策。

    //移动语义(C ++ 11为移动语义服务定义了两个新的函数：移动构造函数和移动赋值运算符)
    //移动语义最好使用与有堆内存指针成员的类，这样可以直接修改堆内存的指针指向
    AutoPtr4(AutoPtr4 &&p):m_ptr(p.m_ptr){
        p.m_ptr = nullptr;
    }
    
   
    
    //移动分配(C ++ 11为移动语义服务定义了两个新的函数：移动构造函数和移动赋值运算符)
    AutoPtr4 &operator=(AutoPtr4 &&p){
        if (&p == this) {
            return *this;
        }
        
        delete m_ptr;
        
        m_ptr = p.m_ptr;
        p.m_ptr = nullptr;
        
        return *this;
    }
    
    
    T &operator*(){return *m_ptr;}
    T *operator->(){return m_ptr;}
    bool isNull() const {return m_ptr == nullptr;}
};

class Resource4
{
public:
    Resource4() { std::cout << "Resource acquired\n"; }
    ~Resource4() { std::cout << "Resource destroyed\n"; }
};

AutoPtr4<Resource4> generateResource2();

/*
 AutoPtr4<Resource4> ap;
 
 ap = generateResource2();
 std::cout << "/////";
 
 //移动语义（赋值右值）
 AutoPtr4<Resource4> ap = AutoPtr4<Resource4>();
 ap = AutoPtr4<Resource4>();
 
 */

#endif /* MoveConsAndAssign2_hpp */
